{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## MoE",
   "id": "4923f827bc90e2d6"
  },
  {
   "attachments": {
    "d6c1fb13-e157-43e3-b5ad-5d516d7bcba0.png": {
     "image/png": "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"
    }
   },
   "cell_type": "markdown",
   "id": "ee7a2bdc-fb73-4a66-9e96-4c2b00b729c2",
   "metadata": {},
   "source": [
    "![MoE.png](attachment:d6c1fb13-e157-43e3-b5ad-5d516d7bcba0.png)"
   ]
  },
  {
   "cell_type": "code",
   "id": "91d7bd0998a22f2f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-27T13:10:39.188119Z",
     "start_time": "2025-07-27T13:10:39.177563Z"
    }
   },
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "from torch import Tensor\n",
    "\n",
    "\n",
    "class ExpertRouter:\n",
    "    def __init__(self, num_experts, gates):\n",
    "        self.gates = gates\n",
    "        self.num_experts = num_experts\n",
    "\n",
    "        # 获取每个样本的前k个专家\n",
    "        _, self.expert_index = torch.topk(gates, k=1, dim=1)\n",
    "\n",
    "        # gates.size(0)表示batch_size\n",
    "        self.batch_index = torch.arange(gates.size(0)).unsqueeze(1)\n",
    "\n",
    "        # 用一个bool_mask记录当前批次中每个样本对应选择的专家，选中的专家为True\n",
    "        self.bool_mask = torch.zeros_like(gates, dtype=torch.bool)\n",
    "        self.bool_mask[self.batch_index, self.expert_index] = True\n",
    "\n",
    "    def dispatch(self, x):\n",
    "        # 每个专家有哪些输入，x中包含了多个样本，每个样本会对应topk个专家，那么某一个专家就有可能会接收多个样本\n",
    "        return [x[self.bool_mask[:, i]] for i in range(self.num_experts)]\n",
    "\n",
    "    def combine(self, expert_outputs: list[Tensor]) -> Tensor:\n",
    "        results = torch.zeros((self.bool_mask.size(0), expert_outputs[0].size(1)))\n",
    "        for i, out in enumerate(expert_outputs):\n",
    "            if out.size(0) > 0:\n",
    "                results[self.bool_mask[:, i]] = out\n",
    "        return results\n",
    "\n",
    "\n",
    "class Expert(nn.Module):\n",
    "    def __init__(self, input_dim, output_dim, hidden_size):\n",
    "        super().__init__()\n",
    "        self.net = nn.Sequential(\n",
    "            nn.Linear(input_dim, hidden_size),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(hidden_size, output_dim)\n",
    "        )\n",
    "\n",
    "    def forward(self, x: Tensor) -> Tensor:\n",
    "        return self.net(x)\n",
    "\n",
    "\n",
    "class MoE(nn.Module):\n",
    "    def __init__(self, input_dim, output_dim, num_experts, hidden_size):\n",
    "        super().__init__()\n",
    "\n",
    "        self.input_dim = input_dim\n",
    "        self.output_dim = output_dim\n",
    "        self.num_experts = num_experts\n",
    "        self.hidden_size = hidden_size\n",
    "\n",
    "        # 专家网络\n",
    "        self.experts = nn.ModuleList(\n",
    "            [Expert(input_dim, output_dim, hidden_size) for _ in range(num_experts)]\n",
    "        )\n",
    "\n",
    "        # 门控网络，对专家进行路由\n",
    "        self.gate = nn.Linear(input_dim, num_experts)\n",
    "\n",
    "    def forward(self, x):\n",
    "        # 得到当前输入x对应的每个专家的权重\n",
    "        gates = F.softmax(self.gate(x), dim=1)  # [batch_size, num_experts]\n",
    "\n",
    "        # 根据专家权重的大小选择topk个专家\n",
    "        router = ExpertRouter(self.num_experts, gates)\n",
    "        expert_inputs = router.dispatch(x)\n",
    "\n",
    "        # 专家处理，把输入数据输入给每个专家，如果某个专家没有输入数据，则返回一个空的张量\n",
    "        expert_outputs = [\n",
    "            self.experts[i](expert_inputs[i]) if expert_inputs[i].size(0) > 0 else\n",
    "            torch.empty(0, self.output_dim)\n",
    "            for i in range(self.num_experts)\n",
    "        ]\n",
    "\n",
    "        # 组合专家输出\n",
    "        outputs = router.combine(expert_outputs)\n",
    "\n",
    "        return outputs"
   ],
   "outputs": [],
   "execution_count": 8
  },
  {
   "cell_type": "code",
   "id": "b520492dbbedc4f5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-27T13:11:07.694978Z",
     "start_time": "2025-07-27T13:11:07.685586Z"
    }
   },
   "source": [
    "input_dim = 64\n",
    "output_dim = 128\n",
    "hidden_size = 256\n",
    "num_experts = 8\n",
    "moe_layer = MoE(input_dim, output_dim, num_experts, hidden_size)\n",
    "\n",
    "# 模拟输入数据\n",
    "batch_size = 4\n",
    "inputs = torch.randn(batch_size, input_dim)\n",
    "\n",
    "outputs = moe_layer(inputs)\n",
    "\n",
    "print(f\"输入形状: {inputs.shape}\")\n",
    "print(f\"输出形状: {outputs.shape}\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入形状: torch.Size([4, 64])\n",
      "输出形状: torch.Size([4, 128])\n"
     ]
    }
   ],
   "execution_count": 9
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
